package com.gxa.ssm251.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

//注册到bean里面
@Component
//声明一个切面
@Aspect
public class LogAspect {
//    前置通知   方法执行前调用  对应注解 @Before
//    后置通知   方法执行后调用  对应注解 @After
//    后置返回通知  方法返回后调用  对应注解 @AfterReturning
//    异常通知(后置抛出通知)   方法出现异常调用 对应注解 @AfterThrowing
//    环绕通知   动态代理、手动推荐方法运行 对应注解 @Around

    //确定切点:为所有的Service的实现类的任意方法
    //* com.gxa.ssm251.service.impl.*.*(..)
    //第一个*:表示任意访问权限
    //com.gxa.ssm251.service.impl 表示类的全路径
    //第二个*:任意类
    //第三个*:任意方法
    //(..):表示任意类型和任意数量的参数情况

    Date date = new Date();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = simpleDateFormat.format(date);
    //            System.out.println(format);
    String filedate = format.substring(0, 10);
    //            System.out.println(filedate);
    String fileName = filedate + ".log";
    String realPath1 = "D:" + File.separator + "log";
    StringBuilder builder = new StringBuilder();
    //写日志进刚刚建的文件
    FileWriter writer = null;
    //先生成log文件夹
    String filepa = realPath1;
    //文件的最终路径
    //生成的log文件夹下的文件
    String filepath = realPath1 + File.separator + fileName;
    File file = new File(filepath);


    //配置一个切点Pointcut
    @Pointcut("execution(* com.gxa.ssm251.service.impl.*.*(..))")
    public void pointCut() {

    }

    //    前置通知
    @Before(value = "pointCut()")
    public void beforeAdvice(JoinPoint joinPoint) throws IOException {
        File file1 = new File(filepa);
        if(!file1.exists())
        {
            file1.mkdir();
            System.out.println("进入了生成文件夹");
        }

//        System.out.println(filepath);//路径测试
        if (!file.exists()) {
            file.createNewFile();
            System.out.println("进入了生成日志文件");
        }
        //写日志进刚刚建的文件
        writer = new FileWriter(file, true);

        //方法名+参数
        String name =format.toString()+"\r\n"+"方法名:"+joinPoint.getSignature().getName().toString()+"\r\n";

        String Andargs="方法参数:"+ Arrays.toString(joinPoint.getArgs()).toString()+"\r\n";
        //把这个内容写到流当中追加
        builder.append(name);
        builder.append(Andargs);
        System.out.println("前置通知");
        //建立一个文件夹

    }

    //    后置通知
    @After(value = "pointCut()")
    public void afterAdvice() throws IOException {
        System.out.println("后置通知");
    }

    //    后置返回通知
    @AfterReturning(value = "pointCut()",returning = "result")
    public void returnAdvice(Object result) throws Throwable {
        //记录执行结果
        if(result!=null){
            String result1 ="执行结果:"+result.toString()+"\r\n"+"--------------------------------"+"\r\n";
            //把这个内容写到流当中追加
            builder.append(result1);
        }

//        System.out.println(result);
        System.out.println("后置返回通知");
        //完成字符串追加后,向流中写
        writer.write(builder.toString());
        writer.flush();
        writer.close();
    }

    //    异常通知(后置抛出通知)
    @AfterThrowing(value = "pointCut()",throwing = "e")
    public void throwingAdvice(Exception e) throws IOException {
        String s = e.toString();
        //异常消息
        String message = e.getMessage();//消息
        StackTraceElement[] stackTrace = e.getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            String s1 ="异常信息:"+stackTraceElement.toString()+"\r\n"+"--------------------------------"+"\r\n";
            //把这个内容写到流当中追加
            builder.append(s1);
        }
        //完成字符串追加后,向流中写
        writer.write(builder.toString());
        writer.flush();
        writer.close();
        System.out.println("后置抛出通知");
    }


    //环绕通知 是最接近于动态代理的,操作要在里面重新写一遍,比较繁琐
//    @Around(value = "pointCut()")
//    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint)  {
//        Object result=null;
//        String name = proceedingJoinPoint.getSignature().getName();
//        try {
//            System.out.println("前置通知");
//            //执行目标方法
//            result= proceedingJoinPoint.proceed();
//
//            System.out.println("后置返回通知");
//
//
//        }catch (Throwable throwable){
//            System.out.println("后置抛出通知");
//        }finally {
//            System.out.println("后置通知");
//        }
//        return result;
//    }


}
